// Author: fruit.com.cn import 'package:flutter/material.dart'; import '../../../core/data/models/drama.dart'; import '../../../core/data/models/watch_progress.dart'; import '../../../core/theme/app_colors.dart'; import '../../../core/widgets/remote_image.dart'; import '../../../l10n/app_localizations.dart'; /// 「我的」页唯一保留的续看入口。 class ContinueWatchingCard extends StatelessWidget { const ContinueWatchingCard({ super.key, required this.drama, required this.record, required this.onResume, this.cardKey = const Key('mine-continue-watching'), this.playButtonKey = const Key('mine-continue-play'), this.progressKey, this.showRemaining = false, }); final Drama drama; final WatchProgress record; final VoidCallback onResume; final Key cardKey; final Key playButtonKey; final Key? progressKey; final bool showRemaining; @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; return Container( key: cardKey, margin: const EdgeInsets.symmetric(horizontal: 14), padding: const EdgeInsets.all(9), decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ ClipRRect( borderRadius: BorderRadius.circular(7), child: RemoteImage(drama.posterUrl, width: 50, height: 64), ), const SizedBox(width: 9), Expanded(child: _info(l10n)), const SizedBox(width: 8), SizedBox( width: 60, height: 28, child: FilledButton( key: playButtonKey, onPressed: onResume, style: FilledButton.styleFrom( backgroundColor: AppColors.blue, foregroundColor: AppColors.onPrimary, padding: EdgeInsets.zero, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(9), ), textStyle: const TextStyle(fontSize: 10), ), child: Text(l10n.resume), ), ), ], ), ); } Widget _info(AppLocalizations l10n) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( l10n.continueWatching, style: const TextStyle( color: AppColors.accent, fontSize: 9, fontWeight: FontWeight.w800, ), ), const SizedBox(height: 2), Text( drama.title, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: AppColors.onSurface, fontSize: 12, fontWeight: FontWeight.w800, ), ), const SizedBox(height: 2), Text( _progressText(l10n), key: progressKey, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(color: AppColors.muted, fontSize: 9), ), ], ); } String _progressText(AppLocalizations l10n) { final episode = drama.episodes.where((item) => item.id == record.episodeId); if (showRemaining) { final number = episode.isEmpty ? 1 : episode.first.number; final remaining = record.duration - record.position; final minutes = remaining.inSeconds <= 0 ? 0 : (remaining.inSeconds / Duration.secondsPerMinute).ceil(); return l10n.episodeRemaining(number, minutes); } final label = episode.isEmpty ? l10n.episodeCount(drama.episodeCount) : l10n.episodeOfTotal(episode.first.number, drama.episodeCount); return '$label · ${_clock(record.position)} / ${_clock(record.duration)}'; } } String _clock(Duration value) { final minutes = value.inMinutes.remainder(60).toString().padLeft(2, '0'); final seconds = value.inSeconds.remainder(60).toString().padLeft(2, '0'); return '$minutes:$seconds'; }