| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- import 'package:flutter/material.dart';
- import 'package:flutter_screenutil/flutter_screenutil.dart';
- import 'package:location/resource/colors.gen.dart';
- import 'package:location/utils/common_expand.dart';
- import 'dart:async';
- import '../../utils/mmkv_util.dart';
- final String MemberDiscountCountdownTimeCount = 'key_member_discount_countdown_time_count';
- class MemberDiscountCountdownWidget extends StatefulWidget {
- final Duration duration; // 倒计时总时长(默认1小时)
- final TextStyle? textStyle;
- final Duration animationDuration;
- final Widget? placeholder;
- final Widget? expiredWidget; // 已过期时显示的组件
- final VoidCallback? onExpired; // 倒计时结束回调
- const MemberDiscountCountdownWidget({
- Key? key,
- this.duration = const Duration(hours: 1),
- this.textStyle,
- this.animationDuration = const Duration(milliseconds: 500),
- this.placeholder,
- this.expiredWidget,
- this.onExpired,
- }) : super(key: key);
- @override
- _MemberDiscountCountdownWidgetState createState() => _MemberDiscountCountdownWidgetState();
- }
- class _MemberDiscountCountdownWidgetState extends State<MemberDiscountCountdownWidget> with SingleTickerProviderStateMixin {
- // 1. 将_timer改为可空类型,移除late
- Timer? _timer;
- bool _isVisible = true;
- bool _isExpired = false;
- DateTime? _startTime;
- Duration? _remainingDuration;
- bool _isLoading = true;
- @override
- void initState() {
- super.initState();
- _loadStartTime();
- }
- Future<void> _loadStartTime() async {
- try {
- final savedTime = KVUtil.getInt(MemberDiscountCountdownTimeCount, 0);
- print("savetimefdifjd---${savedTime}");
- if (savedTime != null && savedTime > 0) {
- _startTime = DateTime.fromMillisecondsSinceEpoch(savedTime);
- _updateRemainingTime();
- if (_remainingDuration != null && _remainingDuration!.isNegative) {
- _handleExpired();
- } else {
- _startTimer();
- }
- } else {
- _startNewCountdown();
- }
- } catch (e) {
- print("加载倒计时时间出错: $e");
- // 异常时调用修复后的_handleExpiredOver
- _handleExpiredOver();
- } finally {
- if (mounted) {
- setState(() {
- _isLoading = false;
- });
- }
- }
- }
- void _startNewCountdown() {
- _startTime = DateTime.now();
- _saveStartTime();
- _updateRemainingTime();
- _startTimer();
- }
- Future<void> _saveStartTime() async {
- try {
- KVUtil.putInt(MemberDiscountCountdownTimeCount, _startTime!.millisecondsSinceEpoch);
- } catch (e) {
- print("保存倒计时时间出错: $e");
- }
- }
- void _startTimer() {
- // 2. 先取消可能存在的旧定时器(避免重复创建)
- _timer?.cancel();
- // 3. 重新创建定时器并赋值
- _timer = Timer.periodic(Duration(seconds: 1), (timer) {
- if (mounted) {
- setState(() {
- _updateRemainingTime();
- if (_remainingDuration != null && _remainingDuration!.isNegative) {
- _handleExpired();
- }
- });
- }
- });
- }
- void _updateRemainingTime() {
- if (_startTime == null) return;
- final now = DateTime.now();
- final endTime = _startTime!.add(widget.duration);
- _remainingDuration = endTime.difference(now);
- }
- void _handleExpired() {
- // 4. 安全取消定时器(允许_timer为null)
- _timer?.cancel();
- _isExpired = true;
- if (mounted) {
- widget.onExpired?.call();
- }
- }
- void _handleExpiredOver() {
- // 5. 修复这里!使用?避免对null调用cancel()
- _timer?.cancel();
- _isExpired = true;
- widget.onExpired?.call();
- }
- @override
- void dispose() {
- // 6. 销毁时安全取消
- _timer?.cancel();
- super.dispose();
- }
- // 以下代码不变...
- String _formatDuration(Duration duration) {
- final hours = duration.inHours;
- final minutes = duration.inMinutes.remainder(60);
- final seconds = duration.inSeconds.remainder(60);
- return '${hours.toString().padLeft(2, '0')} : '
- '${minutes.toString().padLeft(2, '0')} : '
- '${seconds.toString().padLeft(2, '0')}';
- }
- @override
- Widget build(BuildContext context) {
- if (_isLoading) {
- return const CircularProgressIndicator();
- }
- if (_isExpired) {
- return widget.expiredWidget ?? const SizedBox.shrink();
- }
- if (!_isVisible) {
- return widget.placeholder ?? const SizedBox.shrink();
- }
- if (_remainingDuration == null || _remainingDuration!.isNegative) {
- return _createCellWidget("00","00","00");
- }
- final hours = _remainingDuration!.inHours;
- final minutes = _remainingDuration!.inMinutes.remainder(60);
- final seconds = _remainingDuration!.inSeconds.remainder(60);
- final hoursStr = hours.toString().padLeft(2, '0');
- final minutesStr = minutes.toString().padLeft(2, '0');
- final secondsStr = seconds.toString().padLeft(2, '0');
- return _createCellWidget(hoursStr, minutesStr, secondsStr);
- }
- Widget _createCellWidget(String hoursStr, String minutesStr, String secondsStr) {
- return Container(
- child: Row(
- children: [
- Text(
- "优惠限时",
- style: TextStyle(
- color: "#333333".color,
- fontSize: 11.sp,
- fontWeight: FontWeight.w700),
- ),
- SizedBox(width: 5.w),
- _createItemWidget(hoursStr),
- _createItemMidele(),
- _createItemWidget(minutesStr),
- _createItemMidele(),
- _createItemWidget(secondsStr),
- ],
- ),
- );
- }
- Widget _createItemWidget(String timeStr) {
- return Container(
- height: 15.w, // 确保容器有足够高度
- alignment: Alignment.center,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(3),
- color: "#8B79F3".color,
- ),
- padding: EdgeInsets.symmetric(horizontal: 2.w),
- child: Text(
- timeStr,
- style: TextStyle(
- fontSize: 11.sp,
- color: ColorName.white,
- fontWeight: FontWeight.w500,
- ),
- ),
- );
- }
- Widget _createItemMidele() {
- return Container(
- alignment: Alignment.center,
- width: 4.w,
- child: Center(
- child: Text(
- ":",
- style: TextStyle(
- fontSize: 11.sp,
- color: "#8B79F3".color,
- fontWeight: FontWeight.w400)),
- ),
- );
- }
- }
|