/// ============================================================ /// 【PausePopup】暂停答题弹窗 /// (1:1 迁移 Vue components/PausePopup/PausePopup.vue) /// /// - 遮罩 rgba(0,0,0,.7),点击任意位置关闭(onClose) /// - 组件独立秒表:每次 show=true 从 0 开始计时,HH:MM:SS(不足 1 小时隐去小时) /// - 文案:共 {totalCount} 道题,还剩 {remainingCount} 道题待完成 /// ============================================================ library; import 'dart:async'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:new_learn/core/utils/img_url.dart'; import 'exercise_styles.dart'; class PausePopup extends StatefulWidget { const PausePopup({ super.key, required this.show, this.totalCount = 20, this.remainingCount = 0, this.onClose, }); final bool show; final int totalCount; final int remainingCount; final VoidCallback? onClose; @override State createState() => _PausePopupState(); } class _PausePopupState extends State { int _seconds = 0; Timer? _timer; @override void initState() { super.initState(); _syncTimer(widget.show); } @override void didUpdateWidget(covariant PausePopup oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.show != widget.show) { _syncTimer(widget.show); } } @override void dispose() { _stopTimer(); super.dispose(); } void _syncTimer(bool show) { if (show) { _startTimer(); } else { _stopTimer(); } } void _startTimer() { _timer?.cancel(); _seconds = 0; _timer = Timer.periodic(const Duration(seconds: 1), (_) { if (mounted) setState(() => _seconds++); }); } void _stopTimer() { _timer?.cancel(); _timer = null; } String _two(int v) => v < 10 ? '0$v' : '$v'; @override Widget build(BuildContext context) { if (!widget.show) return const SizedBox.shrink(); final isPad = isPadDevice(context); final hours = _seconds ~/ 3600; final showHours = hours > 0; final minutes = (_seconds % 3600) ~/ 60; final secs = _seconds % 60; final unitW = isPad ? 49.w : 44.w; // 88/98rpx final unitH = isPad ? 45.h : 40.h; // 80/90rpx return Positioned.fill( child: GestureDetector( behavior: HitTestBehavior.opaque, onTap: widget.onClose, child: ColoredBox( color: const Color(0xB3000000), // rgba(0,0,0,.7) child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Transform.translate( offset: Offset(isPad ? -35.w : 0, 0), // margin-left: -70rpx child: Container( width: isPad ? 315.5.w : 250.w, // 500/631rpx height: isPad ? 299.5.h : 249.h, // 498/599rpx padding: EdgeInsets.only(top: isPad ? 175.h : 137.5.h), decoration: BoxDecoration( image: DecorationImage( image: CachedNetworkImageProvider( ImgUrl.build( isPad ? '/StaticResource/2026-06-03/conquer-pause-bg-Pad1780466965818.png' : '/StaticResource/2026-04-08/conquer-pause-bg.png', ), ), fit: BoxFit.fill, ), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ if (showHours) ...[ _timeUnit(unitW, unitH, _two(hours)), _timeSep(), ], _timeUnit(unitW, unitH, _two(minutes)), _timeSep(), _timeUnit(unitW, unitH, _two(secs)), ], ), SizedBox(height: 15.h), // margin-t-30 Text.rich( TextSpan( style: TextStyle( fontSize: 13.sp, // 26rpx color: ExerciseColors.subtitle, ), children: [ const TextSpan(text: '共'), TextSpan( text: '${widget.totalCount}', style: const TextStyle( color: Color(0xFF1578FF), ), ), const TextSpan(text: '道题,还剩'), TextSpan( text: '${widget.remainingCount}', style: const TextStyle( color: Color(0xFF1578FF), ), ), const TextSpan(text: '道题待完成'), ], ), ), ], ), ), ), SizedBox(height: 25.h), // margin-t-50 Text( '点击任意位置继续', style: TextStyle( fontSize: 14.sp, // 28rpx color: const Color(0xFFB4C2E0), ), ), ], ), ), ), ), ); } Widget _timeUnit(double w, double h, String text) { return Container( width: w, height: h, alignment: Alignment.center, decoration: BoxDecoration( color: const Color(0xFFF2F8FF), borderRadius: BorderRadius.circular(6.r), boxShadow: [ BoxShadow( color: const Color(0x1A1578FF), offset: Offset(0, 2.h), blurRadius: 6.h, ), ], ), child: Text( text, style: TextStyle( fontSize: 20.sp, // 40rpx fontWeight: FontWeight.w600, color: const Color(0xFF1578FF), ), ), ); } Widget _timeSep() { return Padding( padding: EdgeInsets.symmetric(horizontal: 10.w), // margin-rl-10 + 视觉间距 child: Text( ':', style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.w600, color: const Color(0xFF1578FF), ), ), ); } }