150 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Dart
		
	
	
| 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;
 | ||
| 
 | ||
|   @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();
 | ||
|     if (!_isLoading) {
 | ||
|       _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())
 | ||
|                   : PdfViewPinch(
 | ||
|                 controller: _pdfController,
 | ||
|                 scrollDirection: Axis.vertical,
 | ||
|                 onDocumentLoaded: (document) {
 | ||
|                   setState(() {
 | ||
|                     _totalPages = document.pagesCount;
 | ||
|                   });
 | ||
|                 },
 | ||
|                 onPageChanged: (page) {
 | ||
|                   if (page == _totalPages - 1) {
 | ||
|                     setState(() => _hasScrolledToBottom = true);
 | ||
|                   }
 | ||
|                 },
 | ||
|               ),
 | ||
|             ),
 | ||
|             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,
 | ||
|               ),
 | ||
|             ),
 | ||
|           ],
 | ||
|         ),
 | ||
|       ),
 | ||
|     );
 | ||
|   }
 | ||
| }
 |