Browse Source

表格选择差一个联动

master
hejl 2 months ago
parent
commit
18493fde87
  1. 2
      win_text_editor/lib/framework/controllers/file_provider.dart
  2. 33
      win_text_editor/lib/framework/controllers/tab_items_controller.dart
  3. 21
      win_text_editor/lib/framework/services/file_path_manager.dart
  4. 16
      win_text_editor/lib/framework/widgets/file_explorer_pane.dart
  5. 4
      win_text_editor/lib/main.dart
  6. 10
      win_text_editor/lib/menus/app_menu.dart
  7. 16
      win_text_editor/lib/menus/menu_actions.dart
  8. 5
      win_text_editor/lib/menus/menu_constants.dart
  9. 229
      win_text_editor/lib/modules/memory_table/controllers/memory_table_controller.dart
  10. 123
      win_text_editor/lib/modules/memory_table/services/memory_table_service.dart
  11. 256
      win_text_editor/lib/modules/memory_table/widgets/memory_table_left_side.dart
  12. 106
      win_text_editor/lib/modules/memory_table/widgets/memory_table_right_side.dart
  13. 69
      win_text_editor/lib/modules/memory_table/widgets/memory_table_view.dart
  14. 10
      win_text_editor/lib/modules/module_router.dart
  15. 68
      win_text_editor/lib/modules/uft_file/controllers/tree_view_controller.dart
  16. 145
      win_text_editor/lib/modules/uft_file/controllers/uft_file_controller.dart
  17. 89
      win_text_editor/lib/modules/uft_file/widgets/tree_view.dart
  18. 112
      win_text_editor/lib/modules/uft_file/widgets/uft_file_view.dart
  19. 2
      win_text_editor/lib/shared/components/file_explorer.dart
  20. 184
      win_text_editor/pubspec.lock
  21. 1
      win_text_editor/pubspec.yaml

2
win_text_editor/lib/framework/controllers/file_provider.dart

@ -18,6 +18,8 @@ class FileProvider with ChangeNotifier { @@ -18,6 +18,8 @@ class FileProvider with ChangeNotifier {
// _initFileTree调用
FileProvider();
String? get rootPath => _currentRootPath;
//
Future<void> setRootPath(String path) async {
_currentRootPath = path;

33
win_text_editor/lib/framework/controllers/tab_items_controller.dart

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_js/quickjs/ffi.dart';
import 'package:win_text_editor/framework/models/tab_model.dart';
import 'package:win_text_editor/modules/module_router.dart';
import 'package:win_text_editor/shared/base/base_content_controller.dart';
@ -58,7 +59,6 @@ class TabItemsController with ChangeNotifier { @@ -58,7 +59,6 @@ class TabItemsController with ChangeNotifier {
BaseContentController? get activeContentController {
if (_activeTabId == null) {
Logger().error("没有活动的选项卡ID", source: 'TabItemsController');
return null;
}
final controller = _contentControllers[_activeTabId];
@ -111,7 +111,15 @@ class TabItemsController with ChangeNotifier { @@ -111,7 +111,15 @@ class TabItemsController with ChangeNotifier {
void handleFileDoubleTap(String filePath) {
if (activeContentController == null) {
Logger().error("没有活动的内容控制器", source: 'TabItemsController');
final fileExtension = _getFileExtension(filePath);
switch (fileExtension) {
case 'uftstructure':
openOrActivateTab("内存表", RouterKey.memoryTable, Icons.drive_file_move);
break;
default:
Logger().error("没有活动的内容控制器", source: 'TabItemsController');
}
return;
}
activeContentController?.onOpenFile(filePath);
@ -120,4 +128,25 @@ class TabItemsController with ChangeNotifier { @@ -120,4 +128,25 @@ class TabItemsController with ChangeNotifier {
bool hasController(String tabId) {
return _contentControllers.containsKey(tabId);
}
//
Future<void> openOrActivateTab(String title, String type, IconData icon) async {
try {
final existingTab = _tabs.firstWhereOrNull((tab) => tab.type == type);
if (existingTab != null) {
setActiveTab(existingTab.id);
} else {
final tabId = DateTime.now().millisecondsSinceEpoch.toString();
await addTab(tabId, title: title, type: type, icon: icon, content: "");
}
} catch (e) {
Logger().error("打开或激活标签页失败: $e", source: 'TabItemsController');
}
}
static String _getFileExtension(String filePath) {
final parts = filePath.split('.');
return parts.length > 1 ? parts.last.toLowerCase() : '';
}
}

21
win_text_editor/lib/framework/services/file_path_manager.dart

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
import 'package:shared_preferences/shared_preferences.dart';
import 'package:win_text_editor/framework/controllers/logger.dart';
class FilePathManager {
static const String _lastOpenedFolderKey = 'last_opened_folder';
//
static Future<void> saveLastOpenedFolder(String folderPath) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_lastOpenedFolderKey, folderPath);
Logger().info("保存最新打开的文件夹地址:$folderPath");
}
//
static Future<String?> getLastOpenedFolder() async {
final prefs = await SharedPreferences.getInstance();
final folderPath = prefs.getString(_lastOpenedFolderKey);
Logger().info("加载最后保存的文件夹地址:$folderPath");
return folderPath;
}
}

16
win_text_editor/lib/framework/widgets/file_explorer_pane.dart

@ -2,6 +2,7 @@ import 'package:file_picker/file_picker.dart'; @@ -2,6 +2,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:win_text_editor/framework/controllers/file_provider.dart';
import 'package:win_text_editor/framework/services/file_path_manager.dart';
import 'package:win_text_editor/shared/components/file_explorer.dart';
class FileExplorerPane extends StatelessWidget {
@ -12,6 +13,9 @@ class FileExplorerPane extends StatelessWidget { @@ -12,6 +13,9 @@ class FileExplorerPane extends StatelessWidget {
@override
Widget build(BuildContext context) {
final fileProvider = Provider.of<FileProvider>(context, listen: false);
_loadLastOpenedFolder(fileProvider);
return Consumer<FileProvider>(
builder: (context, fileProvider, child) {
return Material(
@ -67,7 +71,19 @@ class FileExplorerPane extends StatelessWidget { @@ -67,7 +71,19 @@ class FileExplorerPane extends StatelessWidget {
final fileProvider = Provider.of<FileProvider>(context, listen: false);
final String? selectedDirectory = await FilePicker.platform.getDirectoryPath();
if (selectedDirectory != null) {
await FilePathManager.saveLastOpenedFolder(selectedDirectory);
await fileProvider.setRootPath(selectedDirectory);
}
}
Future<void> _loadLastOpenedFolder(FileProvider fileProvider) async {
if (fileProvider.rootPath != null && fileProvider.rootPath!.isNotEmpty) {
return;
}
final String? lastOpenedFolder = await FilePathManager.getLastOpenedFolder();
if (lastOpenedFolder != null) {
await fileProvider.setRootPath(lastOpenedFolder);
}
}
}

4
win_text_editor/lib/main.dart

@ -12,7 +12,7 @@ void main() async { @@ -12,7 +12,7 @@ void main() async {
WindowOptions windowOptions = const WindowOptions(
size: Size(1600, 1000),
center: true,
title: '文件操作工具箱',
title: '编程辅助工具',
);
windowManager.waitUntilReadyToShow(windowOptions, () async {
await windowManager.show();
@ -36,7 +36,7 @@ class MyApp extends StatelessWidget { @@ -36,7 +36,7 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '升级工具',
title: '编程辅助工具',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true, // Material 3

10
win_text_editor/lib/menus/app_menu.dart

@ -14,8 +14,8 @@ class AppMenu extends StatelessWidget { @@ -14,8 +14,8 @@ class AppMenu extends StatelessWidget {
child: Row(
children: [
_buildMenuButton(context, '文件', _buildFileMenuItems()),
_buildMenuButton(context, '工具', _buildToolsMenuItems()),
_buildMenuButton(context, 'AIGC', _buildAigcMenuItems()),
_buildMenuButton(context, '文本工具', _buildToolsMenuItems()),
_buildMenuButton(context, 'UFT工具', _buildUftToolsMenuItems()),
_buildMenuButton(context, '编辑', _buildEditMenuItems()),
_buildMenuButton(context, '窗口', _buildWindowMenuItems()),
_buildMenuButton(context, '帮助', _buildHelpMenuItems()),
@ -50,11 +50,11 @@ class AppMenu extends StatelessWidget { @@ -50,11 +50,11 @@ class AppMenu extends StatelessWidget {
];
}
List<PopupMenuEntry<String>> _buildAigcMenuItems() {
List<PopupMenuEntry<String>> _buildUftToolsMenuItems() {
return [
const PopupMenuItem<String>(
value: MenuConstants.uftFile,
child: ListTile(leading: Icon(Icons.drive_file_move), title: Text('UFT文件')),
value: MenuConstants.memoryTable,
child: ListTile(leading: Icon(Icons.list), title: Text('内存表')),
),
];
}

16
win_text_editor/lib/menus/menu_actions.dart

@ -4,7 +4,6 @@ import 'package:provider/provider.dart'; @@ -4,7 +4,6 @@ import 'package:provider/provider.dart';
import 'package:win_text_editor/framework/controllers/tab_items_controller.dart';
import 'package:win_text_editor/menus/menu_constants.dart';
import 'package:win_text_editor/framework/controllers/file_provider.dart';
import 'package:collection/collection.dart';
import 'dart:io';
import 'package:win_text_editor/modules/module_router.dart';
@ -16,7 +15,7 @@ class MenuActions { @@ -16,7 +15,7 @@ class MenuActions {
MenuConstants.templateParser: _openTemplateParser,
MenuConstants.dataFormat: _dataFormat,
MenuConstants.dataCompare: _dataCompare,
MenuConstants.uftFile: _openUftFile,
MenuConstants.memoryTable: _memoryTable,
MenuConstants.demo: _demo,
MenuConstants.exit: _exitApplication,
};
@ -48,8 +47,8 @@ class MenuActions { @@ -48,8 +47,8 @@ class MenuActions {
await _openOrActivateTab(context, "XML解析", RouterKey.templateParser, Icons.auto_awesome_mosaic);
}
static Future<void> _openUftFile(BuildContext context) async {
await _openOrActivateTab(context, "UFT文件", RouterKey.uftFile, Icons.drive_file_move);
static Future<void> _memoryTable(BuildContext context) async {
await _openOrActivateTab(context, "内存表", RouterKey.memoryTable, Icons.drive_file_move);
}
static Future<void> _dataFormat(BuildContext context) async {
@ -72,14 +71,7 @@ class MenuActions { @@ -72,14 +71,7 @@ class MenuActions {
) async {
try {
final tabManager = Provider.of<TabItemsController>(context, listen: false);
final existingTab = tabManager.tabs.firstWhereOrNull((tab) => tab.type == type);
if (existingTab != null) {
tabManager.setActiveTab(existingTab.id);
} else {
final tabId = DateTime.now().millisecondsSinceEpoch.toString();
await tabManager.addTab(tabId, title: title, type: type, icon: icon, content: "");
}
await tabManager.openOrActivateTab(title, type, icon);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('打开标签页失败: $e')));
}

5
win_text_editor/lib/menus/menu_constants.dart

@ -21,7 +21,10 @@ class MenuConstants { @@ -21,7 +21,10 @@ class MenuConstants {
// AIGC菜单项
static const String aigc = 'aigc';
static const String uftFile = 'uftFile';
//Uft菜单
static const String memoryTable = 'memory_table';
static const String uftTools = 'uft_tools';
//
static const String undo = 'undo';

229
win_text_editor/lib/modules/memory_table/controllers/memory_table_controller.dart

@ -0,0 +1,229 @@ @@ -0,0 +1,229 @@
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:win_text_editor/framework/controllers/logger.dart';
import 'package:win_text_editor/modules/memory_table/services/memory_table_service.dart';
import 'package:win_text_editor/shared/base/base_content_controller.dart';
//
class Field {
Field(this.id, this.name, this.chineseName, this.type, this.remark, [this.isSelected = false]);
final String id; //
final String name; //
final String chineseName; //
final String type; //
final String remark; //
bool isSelected;
}
//
class Index {
Index(this.indexName, this.isPrimary, this.indexFields, this.rule, [this.isSelected = false]);
final String indexName; //
final String isPrimary; //
final String indexFields; //
final String rule; //
bool isSelected;
}
//
class FieldsDataSource extends DataGridSource {
FieldsDataSource(this.fields);
List<Field> fields;
void toggleAllSelection(bool? value) {
for (var field in fields) {
field.isSelected = value ?? false;
}
notifyListeners();
}
void toggleRowSelection(int index, bool? value) {
fields[index].isSelected = value ?? false;
notifyListeners();
}
void updateData(List<Field> newFields) {
fields = newFields;
notifyListeners(); // DataGrid更新
}
@override
List<DataGridRow> get rows =>
fields
.map(
(field) => DataGridRow(
cells: [
DataGridCell<bool>(columnName: 'select', value: field.isSelected),
DataGridCell<String>(columnName: 'id', value: field.id),
DataGridCell<String>(columnName: 'name', value: field.name),
DataGridCell<String>(columnName: 'chineseName', value: field.chineseName),
DataGridCell<String>(columnName: 'type', value: field.type),
DataGridCell<String>(columnName: 'remark', value: field.remark),
],
),
)
.toList();
@override
DataGridRowAdapter? buildRow(DataGridRow row) {
final int rowIndex = effectiveRows.indexOf(row);
return DataGridRowAdapter(
cells:
row.getCells().map<Widget>((dataGridCell) {
if (dataGridCell.columnName == 'select') {
return Center(
child: Checkbox(
value: fields[rowIndex].isSelected,
onChanged: (value) {
toggleRowSelection(rowIndex, value);
},
),
);
}
return Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(dataGridCell.value.toString(), overflow: TextOverflow.ellipsis),
);
}).toList(),
);
}
}
//
class IndexesDataSource extends DataGridSource {
IndexesDataSource(this.indexes);
List<Index> indexes;
void toggleAllSelection(bool? value) {
for (var index in indexes) {
index.isSelected = value ?? false;
}
notifyListeners();
}
void toggleRowSelection(int index, bool? value) {
indexes[index].isSelected = value ?? false;
notifyListeners();
}
void updateData(List<Index> newIndexes) {
indexes = newIndexes;
notifyListeners(); // DataGrid更新
}
@override
List<DataGridRow> get rows =>
indexes
.map(
(index) => DataGridRow(
cells: [
DataGridCell<bool>(columnName: 'select', value: index.isSelected),
DataGridCell<String>(columnName: 'indexName', value: index.indexName),
DataGridCell<String>(columnName: 'isPrimary', value: index.isPrimary),
DataGridCell<String>(columnName: 'indexFields', value: index.indexFields),
DataGridCell<String>(columnName: 'rule', value: index.rule),
],
),
)
.toList();
@override
DataGridRowAdapter? buildRow(DataGridRow row) {
final int rowIndex = effectiveRows.indexOf(row);
return DataGridRowAdapter(
cells:
row.getCells().map<Widget>((dataGridCell) {
if (dataGridCell.columnName == 'select') {
return Center(
child: Checkbox(
value: indexes[rowIndex].isSelected,
onChanged: (value) {
toggleRowSelection(rowIndex, value);
},
),
);
}
return Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(dataGridCell.value.toString(), overflow: TextOverflow.ellipsis),
);
}).toList(),
);
}
bool _getSelectedValue(DataGridRow row) {
final int rowIndex = rows.indexOf(row);
if (rowIndex == -1) {
return false;
}
return indexes[rowIndex].isSelected;
}
}
class MemoryTableController extends BaseContentController {
String? _errorMessage;
String tableName = "";
String objectId = "";
String chineseName = "";
late DataGridSource fieldsSource;
late DataGridSource indexesSource;
late MemoryTableService _service;
MemoryTableController() : _service = MemoryTableService(Logger()) {
//
fieldsSource = FieldsDataSource([
Field('1', '', '', '', ''), // 1
Field('2', '', '', '', ''), // 2
Field('3', '', '', '', ''), // 3
]);
indexesSource = IndexesDataSource([
Index('', '', '', ''), // 1
Index('', '', '', ''), // 2
]);
}
String? get errorMessage => _errorMessage;
@override
Future<void> onOpenFile(String filePath) async {
try {
final tableData = await _service.parseStructureFile(filePath);
// Update controller state
tableName = tableData.tableName;
chineseName = tableData.chineseName;
objectId = tableData.objectId;
// Update data sources
(fieldsSource as FieldsDataSource).updateData(tableData.fields);
(indexesSource as IndexesDataSource).updateData(tableData.indexes);
// Clear any previous error
_errorMessage = null;
// Notify UI to update
notifyListeners();
} catch (e) {
_errorMessage = e.toString();
notifyListeners();
}
}
@override
void onOpenFolder(String folderPath) {
//
}
@override
void dispose() {
super.dispose();
}
}

123
win_text_editor/lib/modules/memory_table/services/memory_table_service.dart

@ -0,0 +1,123 @@ @@ -0,0 +1,123 @@
// memory_table_service.dart
import 'dart:io';
import 'package:win_text_editor/modules/memory_table/controllers/memory_table_controller.dart';
import 'package:xml/xml.dart' as xml;
import 'package:path/path.dart' as path;
import 'package:win_text_editor/framework/controllers/logger.dart';
class MemoryTableService {
final Logger _logger;
MemoryTableService(this._logger);
Future<TableData> parseStructureFile(String filePath) async {
try {
// 1. Check file extension
if (!filePath.toLowerCase().endsWith('.uftstructure')) {
throw const FormatException("文件扩展名必须是.uftstructure");
}
// 2. Read and parse file content
final file = File(filePath);
final content = await file.readAsString();
final document = xml.XmlDocument.parse(content);
final structureNode = document.findAllElements('structure:Structure').firstOrNull;
if (structureNode == null) {
throw const FormatException("文件格式错误:缺少structure:Structure节点");
}
// 3. Get basic info
final fileNameWithoutExt = path.basenameWithoutExtension(filePath);
final chineseName = structureNode.getAttribute('chineseName') ?? '';
final objectId = structureNode.getAttribute('objectId') ?? '';
// 4. Process properties (fields)
final properties = document.findAllElements('properties');
final fields = <Field>[];
int index = 1;
for (final property in properties) {
final id = property.getAttribute('id') ?? '';
fields.add(
Field(
(index++).toString(), //
id, //
'', //
'', //
'', //
),
);
}
// 5. Process indexes
final indexes = document.findAllElements('indexs');
final indexList = <Index>[];
for (final indexNode in indexes) {
final name = indexNode.getAttribute('name') ?? '';
final containerType = indexNode.getAttribute('containerType');
final isPrimary = containerType == null ? '' : '';
final rule = containerType ?? '';
// Get all index fields
final items = indexNode.findAllElements('items');
final fieldsList =
items
.map((item) => item.getAttribute('attrname') ?? '')
.where((f) => f.isNotEmpty)
.toList();
final indexFields = fieldsList.join(',');
indexList.add(
Index(
name, //
isPrimary, //
indexFields, //
rule, //
),
);
}
return TableData(
tableName: fileNameWithoutExt,
chineseName: chineseName,
objectId: objectId,
fields: fields.isNotEmpty ? fields : _getDefaultFields(),
indexes: indexList.isNotEmpty ? indexList : _getDefaultIndexes(),
);
} on xml.XmlParserException catch (e) {
_logger.error("XML解析错误: ${e.message}");
rethrow;
} catch (e) {
_logger.error("处理文件时发生错误: $e");
rethrow;
}
}
List<Field> _getDefaultFields() {
return [Field('1', '', '', '', ''), Field('2', '', '', '', ''), Field('3', '', '', '', '')];
}
List<Index> _getDefaultIndexes() {
return [Index('', '', '', ''), Index('', '', '', '')];
}
}
class TableData {
final String tableName;
final String chineseName;
final String objectId;
final List<Field> fields;
final List<Index> indexes;
TableData({
required this.tableName,
required this.chineseName,
required this.objectId,
required this.fields,
required this.indexes,
});
}

256
win_text_editor/lib/modules/memory_table/widgets/memory_table_left_side.dart

@ -0,0 +1,256 @@ @@ -0,0 +1,256 @@
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:win_text_editor/modules/memory_table/controllers/memory_table_controller.dart';
class MemoryTableLeftSide extends StatelessWidget {
final MemoryTableController controller;
const MemoryTableLeftSide({super.key, required this.controller});
Widget _buildTextFieldRow(String label, String value) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('$label:'),
SizedBox(
width: 200,
child: TextField(
controller: TextEditingController(text: value),
readOnly: true,
decoration: const InputDecoration(isDense: true, contentPadding: EdgeInsets.all(8)),
),
),
],
);
}
Container _buildGridHeader(String text) {
return Container(
alignment: Alignment.center,
color: Colors.grey[200],
child: Text(text, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
);
}
Widget _buildFieldsDataGrid(MemoryTableController controller) {
final fieldsSource = controller.fieldsSource as FieldsDataSource;
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
width: constraints.maxWidth > 800 ? constraints.maxWidth : 800,
child: SfDataGrid(
source: fieldsSource,
gridLinesVisibility: GridLinesVisibility.both,
headerGridLinesVisibility: GridLinesVisibility.both,
columnWidthMode: ColumnWidthMode.fitByCellValue,
selectionMode: SelectionMode.none,
columns: [
GridColumn(
columnName: 'select',
label: _buildCheckboxHeader(
context,
fieldsSource,
controller.fieldsSource.rows.length,
),
width: 60,
),
GridColumn(
columnName: 'id',
label: _buildGridHeader('序号'),
minimumWidth: 80,
),
GridColumn(
columnName: 'name',
label: _buildGridHeader('名称'),
minimumWidth: 120,
),
GridColumn(
columnName: 'chineseName',
label: _buildGridHeader('中文名'),
minimumWidth: 120,
),
GridColumn(
columnName: 'type',
label: _buildGridHeader('类型'),
minimumWidth: 120,
),
GridColumn(
columnName: 'remark',
label: _buildGridHeader('备注'),
minimumWidth: 200,
),
],
onCellTap: (details) {
if (details.column.columnName == 'select') {
final rowIndex = details.rowColumnIndex.rowIndex - 1;
if (rowIndex >= 0 && rowIndex < fieldsSource.fields.length) {
fieldsSource.toggleRowSelection(
rowIndex,
!fieldsSource.fields[rowIndex].isSelected,
);
}
}
},
),
),
);
},
),
),
],
),
);
}
Widget _buildCheckboxHeader(BuildContext context, FieldsDataSource dataSource, int rowCount) {
final allSelected = rowCount > 0 && dataSource.fields.every((item) => item.isSelected);
return Container(
alignment: Alignment.center,
color: Colors.grey[200],
child: Checkbox(
value: allSelected,
tristate: true,
onChanged: (value) {
dataSource.toggleAllSelection(value ?? false);
},
),
);
}
Widget _buildIndexesDataGrid(MemoryTableController controller) {
final indexesSource = controller.indexesSource as IndexesDataSource;
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
width: constraints.maxWidth > 800 ? constraints.maxWidth : 800,
child: SfDataGrid(
source: indexesSource,
gridLinesVisibility: GridLinesVisibility.both,
headerGridLinesVisibility: GridLinesVisibility.both,
columnWidthMode: ColumnWidthMode.fitByCellValue,
columns: [
GridColumn(
columnName: 'select',
label: _buildCheckboxHeaderForIndexes(
context,
indexesSource,
controller.indexesSource.rows.length,
),
width: 60,
),
GridColumn(
columnName: 'indexName',
label: _buildGridHeader('索引名称'),
minimumWidth: 120,
),
GridColumn(
columnName: 'isPrimary',
label: _buildGridHeader('是否主键'),
minimumWidth: 100,
),
GridColumn(
columnName: 'indexFields',
label: _buildGridHeader('索引字段'),
minimumWidth: 150,
),
GridColumn(
columnName: 'rule',
label: _buildGridHeader('规则'),
minimumWidth: 200,
),
],
onCellTap: (details) {
if (details.column.columnName == 'select') {
final rowIndex = details.rowColumnIndex.rowIndex - 1;
if (rowIndex >= 0 && rowIndex < indexesSource.indexes.length) {
indexesSource.toggleRowSelection(
rowIndex,
!indexesSource.indexes[rowIndex].isSelected,
);
}
}
},
),
),
);
},
),
),
],
),
);
}
Widget _buildCheckboxHeaderForIndexes(
BuildContext context,
IndexesDataSource dataSource,
int rowCount,
) {
final allSelected = rowCount > 0 && dataSource.indexes.every((item) => item.isSelected);
return Container(
alignment: Alignment.center,
color: Colors.grey[200],
child: Checkbox(
value: allSelected,
tristate: true,
onChanged: (value) {
dataSource.toggleAllSelection(value ?? false);
},
),
);
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: double.infinity,
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Wrap(
spacing: 16,
runSpacing: 8,
children: [
_buildTextFieldRow('名称', controller.tableName),
_buildTextFieldRow('中文名', controller.chineseName),
_buildTextFieldRow('对象编号', controller.objectId),
],
),
),
),
),
const SizedBox(height: 8),
const Padding(
padding: EdgeInsets.all(8.0),
child: Text('字段列表', style: TextStyle(fontWeight: FontWeight.bold)),
),
Expanded(flex: 6, child: _buildFieldsDataGrid(controller)),
const Padding(
padding: EdgeInsets.all(8.0),
child: Text('索引列表', style: TextStyle(fontWeight: FontWeight.bold)),
),
Expanded(flex: 4, child: _buildIndexesDataGrid(controller)),
],
);
}
}

106
win_text_editor/lib/modules/memory_table/widgets/memory_table_right_side.dart

@ -0,0 +1,106 @@ @@ -0,0 +1,106 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class MemoryTableRightSide extends StatelessWidget {
final TextEditingController codeController;
const MemoryTableRightSide({super.key, required this.codeController});
Widget _buildCheckboxSection() {
return SizedBox(
width: double.infinity,
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Wrap(
spacing: 16,
runSpacing: 8,
children: [
_buildCheckbox('获取记录'),
_buildCheckbox('获取记录数'),
_buildCheckbox('插入记录'),
_buildCheckbox('修改记录'),
_buildCheckbox('删除记录'),
_buildCheckbox('遍历记录'),
],
),
],
),
),
),
);
}
Widget _buildCheckbox(String label) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Checkbox(
value: false, // Replace with your actual value
onChanged: (bool? value) {
// Handle checkbox change
},
),
Text(label),
],
);
}
Widget _buildCodeEditor() {
return Card(
child: Padding(
padding: const EdgeInsets.all(8),
// Expanded
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(4),
),
child: TextField(
controller: codeController,
maxLines: null,
expands: true,
decoration: const InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.all(8),
),
style: const TextStyle(fontFamily: 'monospace'),
),
),
),
);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
_buildCheckboxSection(),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('生成代码:', style: TextStyle(fontWeight: FontWeight.bold)),
IconButton(
icon: const Icon(Icons.content_copy, size: 20),
tooltip: '复制代码',
onPressed: () {
if (codeController.text.isNotEmpty) {
Clipboard.setData(ClipboardData(text: codeController.text));
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('已复制到剪贴板')));
}
},
),
],
),
),
Flexible(child: _buildCodeEditor()),
],
);
}
}

69
win_text_editor/lib/modules/memory_table/widgets/memory_table_view.dart

@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
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/memory_table/controllers/memory_table_controller.dart';
import 'memory_table_left_side.dart';
import 'memory_table_right_side.dart';
class MemoryTableView extends StatefulWidget {
final String tabId;
const MemoryTableView({super.key, required this.tabId});
@override
State<MemoryTableView> createState() => _MemoryTableViewState();
}
class _MemoryTableViewState extends State<MemoryTableView> {
late final MemoryTableController _controller;
final TextEditingController _codeController = TextEditingController();
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 = MemoryTableController();
_isControllerFromTabManager = false;
tabManager.registerController(widget.tabId, _controller);
}
}
@override
void dispose() {
if (!_isControllerFromTabManager) {
_controller.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: _controller,
child: Consumer<MemoryTableController>(
builder: (context, controller, child) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// (50%)
Expanded(flex: 5, child: MemoryTableLeftSide(controller: controller)),
const SizedBox(width: 8),
// (50%)
Expanded(flex: 5, child: MemoryTableRightSide(codeController: _codeController)),
],
),
);
},
),
);
}
}

10
win_text_editor/lib/modules/module_router.dart

@ -7,8 +7,8 @@ import 'package:win_text_editor/modules/data_format/controllers/data_format_cont @@ -7,8 +7,8 @@ import 'package:win_text_editor/modules/data_format/controllers/data_format_cont
import 'package:win_text_editor/modules/data_format/widgets/data_format_view.dart';
import 'package:win_text_editor/modules/demo/controllers/demo_controller.dart';
import 'package:win_text_editor/modules/demo/widgets/demo_view.dart';
import 'package:win_text_editor/modules/uft_file/controllers/uft_file_controller.dart';
import 'package:win_text_editor/modules/uft_file/widgets/uft_file_view.dart';
import 'package:win_text_editor/modules/memory_table/controllers/memory_table_controller.dart';
import 'package:win_text_editor/modules/memory_table/widgets/memory_table_view.dart';
import 'package:win_text_editor/shared/base/base_content_controller.dart';
import 'package:win_text_editor/modules/content_search/controllers/content_search_controller.dart';
import 'package:win_text_editor/modules/template_parser/controllers/template_parser_controller.dart';
@ -21,7 +21,7 @@ class RouterKey { @@ -21,7 +21,7 @@ class RouterKey {
static const String dataFormat = 'data_format';
static const String textEditor = 'text_editor';
static const String dataCompare = 'data_compare';
static const String uftFile = 'uft_file';
static const String memoryTable = 'memory_table';
static const String demo = 'demo';
}
@ -32,7 +32,7 @@ class ModuleRouter { @@ -32,7 +32,7 @@ class ModuleRouter {
RouterKey.templateParser: (tab) => TemplateParserController(),
RouterKey.dataFormat: (tab) => DataFormatController(),
RouterKey.dataCompare: (tab) => DataCompareController(),
RouterKey.uftFile: (tab) => UftFileController(),
RouterKey.memoryTable: (tab) => MemoryTableController(),
RouterKey.demo: (tab) => DemoController(),
};
@ -42,7 +42,7 @@ class ModuleRouter { @@ -42,7 +42,7 @@ class ModuleRouter {
RouterKey.templateParser: (tab, controller) => TemplateParserView(tabId: tab.id),
RouterKey.dataFormat: (tab, controller) => DataFormatView(tabId: tab.id),
RouterKey.dataCompare: (tab, controller) => DataCompareView(tabId: tab.id),
RouterKey.uftFile: (tab, controller) => UftFileView(tabId: tab.id),
RouterKey.memoryTable: (tab, controller) => MemoryTableView(tabId: tab.id),
RouterKey.demo: (tab, controller) => DemoView(tabId: tab.id),
};

68
win_text_editor/lib/modules/uft_file/controllers/tree_view_controller.dart

@ -1,68 +0,0 @@ @@ -1,68 +0,0 @@
// tree_view_controller.dart
import 'package:win_text_editor/shared/models/template_node.dart';
import '../../../shared/base/safe_notifier.dart';
class TreeViewController extends SafeNotifier {
//
List<TemplateNode> _treeNodes = [];
TemplateNode? _selectedNode;
String? _currentParentPath;
List<TemplateNode> get treeNodes => _treeNodes;
TemplateNode? get selectedNode => _selectedNode;
//
void updateTreeNodes(List<TemplateNode> nodes) {
_treeNodes = nodes;
safeNotify();
}
void selectTreeNode(TemplateNode node) {
_selectedNode = node;
safeNotify();
}
// ,
void toggleNodeCheck(TemplateNode node) {
final parentPath = node.path.substring(0, node.path.lastIndexOf('/'));
if (_currentParentPath != null && _currentParentPath != parentPath) {
clearAllChecked();
}
node.isChecked = !node.isChecked;
_currentParentPath = parentPath;
safeNotify();
}
void clearAllChecked() {
void traverse(TemplateNode node) {
node.isChecked = false;
for (var child in node.children) {
traverse(child);
}
}
for (var node in _treeNodes) {
traverse(node);
}
}
List<String> get selectedNodeNames {
List<String> selectedNodeNames = [];
void traverse(TemplateNode node) {
if (node.isChecked) {
selectedNodeNames.add(node.name);
}
for (var child in node.children) {
traverse(child);
}
}
for (var node in _treeNodes) {
traverse(node);
}
return selectedNodeNames;
}
}

145
win_text_editor/lib/modules/uft_file/controllers/uft_file_controller.dart

@ -1,145 +0,0 @@ @@ -1,145 +0,0 @@
import 'package:file_picker/file_picker.dart';
import 'package:win_text_editor/framework/controllers/logger.dart';
import 'package:win_text_editor/shared/models/template_node.dart';
import 'package:win_text_editor/shared/base/base_content_controller.dart';
import 'package:xml/xml.dart' as xml;
import 'dart:io';
import 'tree_view_controller.dart';
class UftFileController extends BaseContentController {
final TreeViewController treeController;
String _filePath = '';
String? _errorMessage;
String get filePath => _filePath;
String? get errorMessage => _errorMessage;
//-------------------
UftFileController() : treeController = TreeViewController() {
_setupCrossControllerCommunication();
}
//
void _setupCrossControllerCommunication() {}
//---------------------
//widget调用入口
Future<void> pickFile() async {
final result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['xml', '*'],
);
if (result != null) {
_filePath = result.files.single.path!;
notifyListeners(); // Consumer
await _loadTemplateData();
}
}
//
Future<void> setFilePath(String path) async {
_filePath = path;
notifyListeners(); // Consumer
await _loadTemplateData();
}
//xml文件
Future<void> _loadTemplateData() async {
try {
_errorMessage = null;
final file = File(_filePath);
final content = await file.readAsString();
final document = xml.XmlDocument.parse(content);
//
//
treeController.updateTreeNodes(
_buildTreeNodes(document.rootElement, document.rootElement.localName, depth: 0),
);
//
} catch (e) {
_errorMessage = 'Failed to load XML: ${e.toString()}';
Logger().error('XML加载错误$_errorMessage');
}
}
//-----------------------------
//
List<TemplateNode> _buildTreeNodes(
xml.XmlElement element,
String path, {
required int depth,
int repreatCount = 1,
}) {
final node = TemplateNode(
path: path,
name: element.qualifiedName,
children: [],
depth: depth,
isExpanded: depth < 5, //
isRepeated: repreatCount > 1,
repreatCount: repreatCount,
);
//
if (element.attributes.isNotEmpty) {
node.children.addAll(
element.attributes.map(
(attr) => TemplateNode(
path: '$path/@${attr.name.local}',
name: '@${attr.qualifiedName}',
children: [],
depth: depth + 1,
isAttribute: true,
),
),
);
}
//
final childElements = element.children.whereType<xml.XmlElement>();
final groupedChildren = <String, List<xml.XmlElement>>{};
//
for (var child in childElements) {
groupedChildren.putIfAbsent(child.name.local, () => []).add(child);
}
//
groupedChildren.forEach((name, elements) {
String path0 = '$path/${elements.first.name.local}';
if (elements.length == 1) {
//
node.children.addAll(_buildTreeNodes(elements.first, path0, depth: depth + 1));
} else {
//
node.children.addAll(
_buildTreeNodes(elements.first, path0, depth: depth + 1, repreatCount: elements.length),
);
}
});
return [node];
}
//
//-------------
@override
void onOpenFile(String filePath) {
setFilePath(filePath);
}
@override
void onOpenFolder(String folderPath) {
//
}
@override
void dispose() {
treeController.dispose();
super.dispose();
}
}

89
win_text_editor/lib/modules/uft_file/widgets/tree_view.dart

@ -1,89 +0,0 @@ @@ -1,89 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:win_text_editor/modules/uft_file/controllers/tree_view_controller.dart';
import 'package:win_text_editor/shared/models/template_node.dart';
import 'package:win_text_editor/shared/components/tree_view.dart';
class FileTreeView extends StatelessWidget {
const FileTreeView({super.key});
@override
Widget build(BuildContext context) {
return Consumer<TreeViewController>(
builder: (context, controller, _) {
if (controller.treeNodes.isEmpty) {
return const Center(child: Text('No XML data available'));
}
return TreeView(
nodes: controller.treeNodes,
config: const TreeViewConfig(
showIcons: true,
singleSelect: true,
selectedColor: Colors.lightBlueAccent,
icons: {'element': Icons.label_outline, 'attribute': Icons.code},
),
onNodeTap: (node) {
controller.selectTreeNode;
},
nodeBuilder: (context, node, isSelected, onTap) {
return _buildTreeNode(node, isSelected, onTap, controller);
},
);
},
);
}
Widget _buildTreeNode(
TreeNode node,
bool isSelected,
VoidCallback onTap,
TreeViewController controller,
) {
final templateNode = node as TemplateNode;
final isAttribute = node.isAttribute;
final isActuallySelected = controller.selectedNode?.id == templateNode.id;
return Container(
color: isActuallySelected ? Colors.lightBlueAccent.withOpacity(0.2) : Colors.transparent,
child: Padding(
padding: EdgeInsets.only(left: 12.0 * node.depth),
child: ListTile(
dense: true,
leading: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (templateNode.children.isEmpty) //
Checkbox(
value: templateNode.isChecked,
onChanged: (value) {
if (value != null) {
controller.toggleNodeCheck(templateNode);
}
},
),
isAttribute
? const Icon(Icons.code, size: 16, color: Colors.grey)
: const Icon(Icons.label_outline, size: 18, color: Colors.blue),
],
),
title: Text(
isAttribute ? templateNode.name.substring(1) : templateNode.name,
style: TextStyle(
color: isAttribute ? Colors.grey[600] : Colors.black,
fontWeight: isAttribute ? FontWeight.normal : FontWeight.w500,
),
),
trailing:
templateNode.isRepeated
? Text(
"(${templateNode.repreatCount.toString()})",
style: const TextStyle(color: Colors.grey),
)
: null,
onTap: onTap,
),
),
);
}
}

112
win_text_editor/lib/modules/uft_file/widgets/uft_file_view.dart

@ -1,112 +0,0 @@ @@ -1,112 +0,0 @@
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/uft_file/controllers/uft_file_controller.dart';
import 'package:win_text_editor/modules/uft_file/widgets/tree_view.dart';
class UftFileView extends StatefulWidget {
final String tabId;
const UftFileView({super.key, required this.tabId});
@override
State<UftFileView> createState() => _UftFileViewState();
}
class _UftFileViewState extends State<UftFileView> {
late final UftFileController _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 = UftFileController();
_isControllerFromTabManager = false;
tabManager.registerController(widget.tabId, _controller);
}
}
@override
void dispose() {
if (!_isControllerFromTabManager) {
_controller.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: _controller),
ChangeNotifierProvider.value(value: _controller.treeController),
],
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
_buildFilePathInput(),
const SizedBox(height: 8),
Expanded(child: _buildMainContent()),
],
),
),
);
}
Widget _buildFilePathInput() {
return Consumer<UftFileController>(
builder: (context, controller, _) {
return TextField(
decoration: InputDecoration(
labelText: 'UFT File',
hintText: 'UFT 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,
);
},
);
}
Widget _buildMainContent() {
return Consumer<UftFileController>(
builder: (context, controller, _) {
if (controller.errorMessage != null) {
return Center(child: Text(controller.errorMessage!));
}
return Row(
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.3,
child: const Column(
children: [
Expanded(flex: 2, child: Card(child: FileTreeView())),
SizedBox(height: 8),
Expanded(flex: 4, child: Card(child: Text("UFT File Content1"))),
],
),
),
const SizedBox(width: 8),
const Expanded(child: Card(child: Text("UFT File Content2"))),
],
);
},
);
}
}

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

@ -3,6 +3,7 @@ import 'dart:math'; @@ -3,6 +3,7 @@ import 'dart:math';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:win_text_editor/framework/services/file_path_manager.dart';
import '../../framework/models/file_node.dart';
import '../../framework/controllers/file_provider.dart';
@ -26,6 +27,7 @@ class _FileExplorerState extends State<FileExplorer> { @@ -26,6 +27,7 @@ class _FileExplorerState extends State<FileExplorer> {
final String? selectedDirectory = await FilePicker.platform.getDirectoryPath();
if (selectedDirectory != null) {
await FilePathManager.saveLastOpenedFolder(selectedDirectory);
await fileProvider.setRootPath(selectedDirectory);
}
}

184
win_text_editor/pubspec.lock

@ -6,7 +6,7 @@ packages: @@ -6,7 +6,7 @@ packages:
description:
name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
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://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
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://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
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://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
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://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
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://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
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://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
characters:
@ -62,7 +62,7 @@ packages: @@ -62,7 +62,7 @@ packages:
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
clock:
@ -70,7 +70,7 @@ packages: @@ -70,7 +70,7 @@ packages:
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
collection:
@ -78,7 +78,7 @@ packages: @@ -78,7 +78,7 @@ packages:
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
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://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "0.3.4+2"
csv:
@ -94,7 +94,7 @@ packages: @@ -94,7 +94,7 @@ packages:
description:
name: csv
sha256: c6aa2679b2a18cb57652920f674488d89712efaf4d3fdf2e537215b35fc19d6c
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
expandable:
@ -102,7 +102,7 @@ packages: @@ -102,7 +102,7 @@ packages:
description:
name: expandable
sha256: "9604d612d4d1146dafa96c6d8eec9c2ff0994658d6d09fed720ab788c7f5afc2"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "5.0.1"
fake_async:
@ -110,7 +110,7 @@ packages: @@ -110,7 +110,7 @@ packages:
description:
name: fake_async
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
ffi:
@ -118,15 +118,23 @@ packages: @@ -118,15 +118,23 @@ packages:
description:
name: ffi
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
file_picker:
dependency: "direct main"
description:
name: file_picker
sha256: "77f8e81d22d2a07d0dee2c62e1dda71dc1da73bf43bb2d45af09727406167964"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "10.1.9"
flutter:
@ -139,7 +147,7 @@ packages: @@ -139,7 +147,7 @@ packages:
description:
name: flutter_js
sha256: "0d22d73a474b5b80c3ab5508e7c3eab6fb20beea9dec45bbd21088cfd27a5e61"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "0.8.3"
flutter_lints:
@ -147,7 +155,7 @@ packages: @@ -147,7 +155,7 @@ packages:
description:
name: flutter_lints
sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.0.3"
flutter_plugin_android_lifecycle:
@ -155,7 +163,7 @@ packages: @@ -155,7 +163,7 @@ packages:
description:
name: flutter_plugin_android_lifecycle
sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.0.28"
flutter_syntax_view:
@ -163,7 +171,7 @@ packages: @@ -163,7 +171,7 @@ packages:
description:
name: flutter_syntax_view
sha256: c5017bbedfdcf538daba765e16541fcb26434071655ca00cea7cbc205a70246a
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "4.1.7"
flutter_test:
@ -181,7 +189,7 @@ packages: @@ -181,7 +189,7 @@ packages:
description:
name: http
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
http_parser:
@ -189,7 +197,7 @@ packages: @@ -189,7 +197,7 @@ packages:
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
leak_tracker:
@ -197,7 +205,7 @@ packages: @@ -197,7 +205,7 @@ packages:
description:
name: leak_tracker
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "10.0.8"
leak_tracker_flutter_testing:
@ -205,7 +213,7 @@ packages: @@ -205,7 +213,7 @@ packages:
description:
name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "3.0.9"
leak_tracker_testing:
@ -213,7 +221,7 @@ packages: @@ -213,7 +221,7 @@ packages:
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
lints:
@ -221,7 +229,7 @@ packages: @@ -221,7 +229,7 @@ packages:
description:
name: lints
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
matcher:
@ -229,7 +237,7 @@ packages: @@ -229,7 +237,7 @@ packages:
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "0.12.17"
material_color_utilities:
@ -237,7 +245,7 @@ packages: @@ -237,7 +245,7 @@ packages:
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "0.11.1"
meta:
@ -245,7 +253,7 @@ packages: @@ -245,7 +253,7 @@ packages:
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.16.0"
mustache_template:
@ -253,7 +261,7 @@ packages: @@ -253,7 +261,7 @@ packages:
description:
name: mustache_template
sha256: a46e26f91445bfb0b60519be280555b06792460b27b19e2b19ad5b9740df5d1c
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
nested:
@ -261,7 +269,7 @@ packages: @@ -261,7 +269,7 @@ packages:
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
path:
@ -269,7 +277,7 @@ packages: @@ -269,7 +277,7 @@ packages:
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
path_provider:
@ -277,7 +285,7 @@ packages: @@ -277,7 +285,7 @@ packages:
description:
name: path_provider
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.1.5"
path_provider_android:
@ -285,7 +293,7 @@ packages: @@ -285,7 +293,7 @@ packages:
description:
name: path_provider_android
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.2.17"
path_provider_foundation:
@ -293,7 +301,7 @@ packages: @@ -293,7 +301,7 @@ packages:
description:
name: path_provider_foundation
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
path_provider_linux:
@ -301,7 +309,7 @@ packages: @@ -301,7 +309,7 @@ packages:
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
@ -309,7 +317,7 @@ packages: @@ -309,7 +317,7 @@ packages:
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
path_provider_windows:
@ -317,7 +325,7 @@ packages: @@ -317,7 +325,7 @@ packages:
description:
name: path_provider_windows
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
petitparser:
@ -325,7 +333,7 @@ packages: @@ -325,7 +333,7 @@ packages:
description:
name: petitparser
sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "6.1.0"
platform:
@ -333,7 +341,7 @@ packages: @@ -333,7 +341,7 @@ packages:
description:
name: platform
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "3.1.6"
plugin_platform_interface:
@ -341,7 +349,7 @@ packages: @@ -341,7 +349,7 @@ packages:
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.1.8"
provider:
@ -349,7 +357,7 @@ packages: @@ -349,7 +357,7 @@ packages:
description:
name: provider
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "6.1.5"
screen_retriever:
@ -357,9 +365,65 @@ packages: @@ -357,9 +365,65 @@ packages:
description:
name: screen_retriever
sha256: "6ee02c8a1158e6dae7ca430da79436e3b1c9563c8cf02f524af997c201ac2b90"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "0.1.9"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
url: "https://pub.dev"
source: hosted
version: "2.5.3"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
url: "https://pub.dev"
source: hosted
version: "2.4.10"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
sky_engine:
dependency: transitive
description: flutter
@ -370,7 +434,7 @@ packages: @@ -370,7 +434,7 @@ packages:
description:
name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.10.1"
stack_trace:
@ -378,7 +442,7 @@ packages: @@ -378,7 +442,7 @@ packages:
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
stream_channel:
@ -386,7 +450,7 @@ packages: @@ -386,7 +450,7 @@ packages:
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
string_scanner:
@ -394,7 +458,7 @@ packages: @@ -394,7 +458,7 @@ packages:
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
sync_http:
@ -402,7 +466,7 @@ packages: @@ -402,7 +466,7 @@ packages:
description:
name: sync_http
sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "0.3.1"
syncfusion_flutter_core:
@ -410,7 +474,7 @@ packages: @@ -410,7 +474,7 @@ packages:
description:
name: syncfusion_flutter_core
sha256: a2427697bfad5b611db78ea4c4daef82d3350b83c729a8dc37959662a31547f9
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "23.2.7"
syncfusion_flutter_datagrid:
@ -418,7 +482,7 @@ packages: @@ -418,7 +482,7 @@ packages:
description:
name: syncfusion_flutter_datagrid
sha256: "9f621f6344d2ed7ea3a8d0ff5c145c174f1e227d6d8851290591ceb718e44600"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "23.2.7"
term_glyph:
@ -426,7 +490,7 @@ packages: @@ -426,7 +490,7 @@ packages:
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
test_api:
@ -434,7 +498,7 @@ packages: @@ -434,7 +498,7 @@ packages:
description:
name: test_api
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "0.7.4"
typed_data:
@ -442,7 +506,7 @@ packages: @@ -442,7 +506,7 @@ packages:
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vector_math:
@ -450,7 +514,7 @@ packages: @@ -450,7 +514,7 @@ packages:
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
vm_service:
@ -458,7 +522,7 @@ packages: @@ -458,7 +522,7 @@ packages:
description:
name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "14.3.1"
web:
@ -466,7 +530,7 @@ packages: @@ -466,7 +530,7 @@ packages:
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
win32:
@ -474,7 +538,7 @@ packages: @@ -474,7 +538,7 @@ packages:
description:
name: win32
sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "5.13.0"
window_manager:
@ -482,7 +546,7 @@ packages: @@ -482,7 +546,7 @@ packages:
description:
name: window_manager
sha256: "8699323b30da4cdbe2aa2e7c9de567a6abd8a97d9a5c850a3c86dcd0b34bbfbf"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "0.3.9"
xdg_directories:
@ -490,7 +554,7 @@ packages: @@ -490,7 +554,7 @@ packages:
description:
name: xdg_directories
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
xml:
@ -498,7 +562,7 @@ packages: @@ -498,7 +562,7 @@ packages:
description:
name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
url: "https://pub.dev"
source: hosted
version: "6.5.0"
sdks:

1
win_text_editor/pubspec.yaml

@ -23,6 +23,7 @@ dependencies: @@ -23,6 +23,7 @@ dependencies:
xml: ^6.5.0
csv: ^6.0.0
mustache_template: ^2.0.0
shared_preferences: ^2.2.1
dev_dependencies:
flutter_test:

Loading…
Cancel
Save