flutter_integrated_whb/lib/customWidget/remote_file_page.dart

179 lines
5.2 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:pdfx/pdfx.dart';
import 'package:path_provider/path_provider.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:dio/dio.dart';
import 'package:qhd_prevention/tools/tools.dart';
class RemoteFilePage extends StatefulWidget {
final String fileUrl;
final int countdownSeconds;
const RemoteFilePage({
Key? key,
required this.fileUrl,
this.countdownSeconds = 3,
}) : super(key: key);
@override
_RemoteFilePageState createState() => _RemoteFilePageState();
}
class _RemoteFilePageState extends State<RemoteFilePage> {
String? _localPath;
bool _isLoading = true;
bool _hasScrolledToBottom = false;
bool _timerFinished = false;
late int _secondsRemaining;
Timer? _countdownTimer;
late PdfControllerPinch _pdfController;
int _totalPages = 0;
// 用于短文档(<=3页)的停留计时器兜底
Timer? _pageViewTimer;
@override
void initState() {
super.initState();
_secondsRemaining = widget.countdownSeconds;
_startCountdown();
_downloadAndLoad();
LoadingDialogHelper.hide();
}
Future<void> _downloadAndLoad() async {
try {
final url = widget.fileUrl;
final filename = url.split('/').last;
final dir = await getTemporaryDirectory();
final filePath = '${dir.path}/$filename';
final dio = Dio();
final response = await dio.get<List<int>>(
url,
options: Options(responseType: ResponseType.bytes),
);
final file = File(filePath);
await file.writeAsBytes(response.data!);
// 加载 PDF 控制器
_pdfController = PdfControllerPinch(
document: PdfDocument.openFile(filePath),
);
setState(() {
_localPath = filePath;
_isLoading = false;
});
} catch (e) {
// 下载或加载失败
setState(() {
_isLoading = false;
});
ToastUtil.showNormal(context, '文件加载失败: $e');
}
}
void _startCountdown() {
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
setState(() {
if (_secondsRemaining > 1) {
_secondsRemaining--;
} else {
_secondsRemaining = 0;
_timerFinished = true;
_countdownTimer?.cancel();
}
});
});
}
@override
void dispose() {
_countdownTimer?.cancel();
_pageViewTimer?.cancel();
if (!_isLoading) {
_pdfController.dispose();
}
super.dispose();
}
// 当页面改变时调用pdfx 的 page 是 1-based
void _onPageChanged(int page) {
// 取消可能存在的短页面计时器(重新开始)
_pageViewTimer?.cancel();
// 如果到达最后一页(注意页码从 1 开始)
if (_totalPages > 0 && page >= _totalPages) {
// 直接标记为已翻到底
setState(() => _hasScrolledToBottom = true);
return;
}
// 对于特别短的文档(例如 <=3 页),我们做一个停留计时器:如果用户停留在最后一页一小段时间,也视为已浏览完毕
if (_totalPages > 0 && _totalPages <= 3) {
// 如果当前页已经是最后一页page == _totalPages启动短计时器
if (page == _totalPages) {
_pageViewTimer = Timer(const Duration(seconds: 1), () {
if (mounted) setState(() => _hasScrolledToBottom = true);
});
}
}
}
@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())
: PdfViewPinch(
controller: _pdfController,
scrollDirection: Axis.vertical,
onDocumentLoaded: (document) {
setState(() {
_totalPages = document.pagesCount;
// 如果文档只有 1 页,直接视为已看完
if (_totalPages <= 1) {
_hasScrolledToBottom = true;
}
});
},
onPageChanged: (page) {
_onPageChanged(page);
},
),
),
Padding(
padding: const EdgeInsets.all(16),
child: CustomButton(
backgroundColor: isButtonEnabled ? Colors.blue : Colors.grey,
text: isButtonEnabled
? '我已学习完毕'
: _secondsRemaining == 0 ? '我已学习完毕' : '$_secondsRemaining s我已学习完毕',
onPressed: isButtonEnabled
? () {
// TODO: 完成回调
Navigator.pop(context, true);
}
: null,
),
),
],
),
),
);
}
}