Browse Source

能够加载小于10M的文件了

master
hejl 2 months ago
parent
commit
b06ecf4811
  1. 2
      win_text_editor/lib/app/providers/editor_provider.dart
  2. 87
      win_text_editor/lib/app/widgets/text_tab.dart

2
win_text_editor/lib/app/providers/editor_provider.dart

@ -51,7 +51,7 @@ class EditorProvider with ChangeNotifier {
if (name != null) { if (name != null) {
tab.fileName = name; tab.fileName = name;
} }
Logger().debug("内容更新成功,文件:${tab.fileName}, ${tab.content.length}"); // Logger().debug("内容更新成功,文件:${tab.fileName}, ${tab.content.length}");
notifyListeners(); notifyListeners();
} catch (e) { } catch (e) {
Logger().error("更新内容失败: ${e.toString()}", source: 'EditorProvider'); Logger().error("更新内容失败: ${e.toString()}", source: 'EditorProvider');

87
win_text_editor/lib/app/widgets/text_tab.dart

@ -1,11 +1,11 @@
import 'dart:convert';
import 'dart:ui'; import 'dart:ui';
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter/services.dart'; // import 'package:flutter/services.dart';
import 'package:win_text_editor/app/providers/editor_provider.dart'; import 'package:win_text_editor/app/providers/editor_provider.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'dart:io';
class TextTab extends StatefulWidget { class TextTab extends StatefulWidget {
final String tabId; final String tabId;
@ -21,8 +21,9 @@ class _TextTabState extends State<TextTab> {
late EditorProvider _provider; late EditorProvider _provider;
late FocusNode _focusNode; late FocusNode _focusNode;
late ScrollController _scrollController; late ScrollController _scrollController;
bool _isLoading = false;
static const int maxFileSize = 10 * 1024 * 1024; // 10MB
@override
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -51,7 +52,7 @@ class _TextTabState extends State<TextTab> {
void dispose() { void dispose() {
_controller.dispose(); _controller.dispose();
_focusNode.dispose(); _focusNode.dispose();
_scrollController.dispose(); // _scrollController.dispose();
super.dispose(); super.dispose();
} }
@ -80,7 +81,7 @@ class _TextTabState extends State<TextTab> {
IconButton( IconButton(
icon: const Icon(Icons.folder_open, size: 20), icon: const Icon(Icons.folder_open, size: 20),
tooltip: '打开文件', tooltip: '打开文件',
onPressed: () => _openFile(context), onPressed: _isLoading ? null : () => _openFile(context),
), ),
IconButton( IconButton(
icon: const Icon(Icons.content_copy, size: 20), icon: const Icon(Icons.content_copy, size: 20),
@ -93,6 +94,15 @@ class _TextTabState extends State<TextTab> {
tooltip: '保存到文件', tooltip: '保存到文件',
onPressed: tab.content.isEmpty ? null : () => _saveFile(context, tab.content), onPressed: tab.content.isEmpty ? null : () => _saveFile(context, tab.content),
), ),
if (_isLoading)
const Padding(
padding: EdgeInsets.only(left: 8),
child: SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(strokeWidth: 2),
),
),
], ],
), ),
], ],
@ -105,10 +115,9 @@ class _TextTabState extends State<TextTab> {
dragDevices: {PointerDeviceKind.touch, PointerDeviceKind.mouse}, dragDevices: {PointerDeviceKind.touch, PointerDeviceKind.mouse},
), ),
child: SingleChildScrollView( child: SingleChildScrollView(
controller: _scrollController, // controller: _scrollController,
child: Stack( child: Stack(
children: [ children: [
// TextField
TextField( TextField(
controller: _controller, controller: _controller,
focusNode: _focusNode, focusNode: _focusNode,
@ -121,7 +130,7 @@ class _TextTabState extends State<TextTab> {
style: TextStyle( style: TextStyle(
fontFamily: 'monospace', fontFamily: 'monospace',
fontSize: 14, fontSize: 14,
color: Theme.of(context).textTheme.bodyLarge?.color, // 使 color: Theme.of(context).textTheme.bodyLarge?.color,
), ),
), ),
], ],
@ -135,34 +144,74 @@ class _TextTabState extends State<TextTab> {
Future<void> _openFile(BuildContext context) async { Future<void> _openFile(BuildContext context) async {
try { try {
setState(() => _isLoading = true);
final result = await FilePicker.platform.pickFiles(type: FileType.any, allowMultiple: false); final result = await FilePicker.platform.pickFiles(type: FileType.any, allowMultiple: false);
if (result != null && result.files.single.path != null) { if (result != null && result.files.single.path != null) {
final file = File(result.files.single.path!); final file = File(result.files.single.path!);
final content = await file.readAsString(); final fileSize = await file.length();
//
if (fileSize > maxFileSize) {
if (context.mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('文件过大(超过10MB),无法处理')));
}
return;
}
//
_provider.updateContent(widget.tabId, '', result.files.first.name);
_controller.text = '';
//
final stream = file.openRead();
final lines = stream.transform(utf8.decoder).transform(const LineSplitter());
// provider和控制器 await for (final line in lines) {
_provider.updateContent(widget.tabId, content, result.files.first.name); if (!mounted) break; //
_controller.text = content; //
setState(() {
_controller.text += '$line\n';
_provider.updateContent(widget.tabId, _controller.text, result.files.first.name);
});
//
WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
});
//
await Future.delayed(const Duration(milliseconds: 10));
}
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('已加载: ${file.path}'))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('已加载: ${file.path}')));
} }
} }
} on FormatException { } on FormatException {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('这不是可读的文本文件'))); if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('这不是可读的文本文件')));
}
} on FileSystemException catch (e) { } on FileSystemException catch (e) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('文件访问错误: ${e.message}'))); if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('文件访问错误: ${e.message}')));
}
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of( ScaffoldMessenger.of(
context, context,
).showSnackBar(SnackBar(content: Text('读取失败: ${e.toString()}'))); ).showSnackBar(SnackBar(content: Text('读取失败: ${e.toString()}')));
} }
} finally {
if (mounted) {
setState(() => _isLoading = false);
}
} }
} }
//
Future<void> _copyToClipboard(BuildContext context, String content) async { Future<void> _copyToClipboard(BuildContext context, String content) async {
await Clipboard.setData(ClipboardData(text: content)); await Clipboard.setData(ClipboardData(text: content));
if (context.mounted) { if (context.mounted) {
@ -170,11 +219,8 @@ class _TextTabState extends State<TextTab> {
} }
} }
//
//
Future<void> _saveFile(BuildContext context, String content) async { Future<void> _saveFile(BuildContext context, String content) async {
try { try {
//
String? outputPath = await FilePicker.platform.saveFile( String? outputPath = await FilePicker.platform.saveFile(
dialogTitle: '保存文件', dialogTitle: '保存文件',
fileName: 'untitled.txt', fileName: 'untitled.txt',
@ -186,9 +232,7 @@ class _TextTabState extends State<TextTab> {
final file = File(outputPath); final file = File(outputPath);
//
if (await file.exists()) { if (await file.exists()) {
//
final shouldOverwrite = await showDialog<bool>( final shouldOverwrite = await showDialog<bool>(
context: context, context: context,
builder: builder:
@ -211,7 +255,6 @@ class _TextTabState extends State<TextTab> {
if (shouldOverwrite != true) return; if (shouldOverwrite != true) return;
} }
//
await file.writeAsString(content); await file.writeAsString(content);
if (context.mounted) { if (context.mounted) {

Loading…
Cancel
Save