QinGang_interested/lib/customWidget/read_file_page.dart

203 lines
5.3 KiB
Dart
Raw Permalink Normal View History

2026-04-08 15:03:56 +08:00
import 'dart:async';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:docx_viewer/docx_viewer.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pdfx/pdfx.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
class ReadFilePage extends StatefulWidget {
final String fileUrl;
final int countdownSeconds;
const ReadFilePage({
Key? key,
required this.fileUrl,
this.countdownSeconds = 3,
}) : super(key: key);
@override
State<ReadFilePage> createState() => _ReadFilePageState();
}
class _ReadFilePageState extends State<ReadFilePage> {
String? _localPath;
bool _isLoading = true;
bool _hasScrolledToBottom = false;
bool _timerFinished = false;
late int _secondsRemaining;
Timer? _countdownTimer;
PdfControllerPinch? _pdfController;
int _totalPages = 0;
bool _isDocxFile = false;
@override
void initState() {
super.initState();
_secondsRemaining = widget.countdownSeconds;
_startCountdown();
_prepareFile();
}
bool _isDocxUrl(String url) {
final path = Uri.parse(url).path.toLowerCase();
return path.endsWith('.docx') || path.endsWith('.doc');
}
bool _isPdfUrl(String url) {
final path = Uri.parse(url).path.toLowerCase();
return path.endsWith('.pdf');
}
Future<void> _prepareFile() async {
final url = widget.fileUrl;
if (_isDocxUrl(url)) {
if (!mounted) return;
setState(() {
_isDocxFile = true;
_isLoading = false;
});
return;
}
if (!_isPdfUrl(url)) {
if (!mounted) return;
setState(() {
_isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('目前仅支持 PDF、DOCX、DOC 文件预览')),
);
return;
}
await _downloadAndLoadPdf();
}
Future<void> _downloadAndLoadPdf() async {
try {
final url = widget.fileUrl;
final uri = Uri.parse(url);
final filename = uri.pathSegments.isNotEmpty ? uri.pathSegments.last : 'temp.pdf';
final dir = await getTemporaryDirectory();
final filePath = '${dir.path}/$filename';
final dio = Dio();
await dio.download(url, filePath);
if (!mounted) return;
_pdfController = PdfControllerPinch(
document: PdfDocument.openFile(filePath),
);
setState(() {
_localPath = filePath;
_isLoading = false;
});
} catch (e) {
if (!mounted) return;
setState(() {
_isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('文件加载失败:$e')),
);
}
}
void _startCountdown() {
_countdownTimer?.cancel();
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (!mounted) return;
setState(() {
if (_secondsRemaining > 1) {
_secondsRemaining--;
} else {
_secondsRemaining = 0;
_timerFinished = true;
_countdownTimer?.cancel();
}
});
});
}
@override
void dispose() {
_countdownTimer?.cancel();
_pdfController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final isButtonEnabled = _timerFinished && _hasScrolledToBottom;
return Scaffold(
appBar: MyAppbar(title: '文件详情'),
backgroundColor: Colors.white,
body: SafeArea(
child: Column(
children: [
Expanded(
child: _isLoading
? const Center(child: CircularProgressIndicator())
: _isDocxFile
? DocxView(
filePath: widget.fileUrl,
fontSize: 16,
onError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('DOCX 加载失败:$error')),
);
},
)
: _pdfController == null
? const Center(
child: Text('文件无法预览,请确认链接有效且为 PDF 文件'),
)
: PdfViewPinch(
controller: _pdfController!,
scrollDirection: Axis.vertical,
onDocumentLoaded: (document) {
setState(() {
_totalPages = document.pagesCount;
});
},
onPageChanged: (page) {
if (_totalPages > 0 && page == _totalPages - 1) {
setState(() => _hasScrolledToBottom = true);
}
},
),
),
// Padding(
// padding: const EdgeInsets.all(16),
// child: ElevatedButton(
// onPressed: isButtonEnabled
// ? () {
// Navigator.pop(context);
// }
// : null,
// child: Text(
// isButtonEnabled
// ? '我已学习完毕'
// : _secondsRemaining == 0
// ? '请阅读完成'
// : '$_secondsRemaining s我已学习完毕',
// ),
// ),
// ),
],
),
),
);
}
}